namespace AutoTest.Console
{
    using System;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using Core.Messaging;
    using Core.TestRunners;
    using log4net;

    public class BuildChanged : IConsumerOf<FileChangeMessage>
    {
        static readonly ILog _logger = LogManager.GetLogger(typeof(BuildChanged));
        readonly ITestRunner _testRunner;

        public BuildChanged(ITestRunner testRunner)
        {
            _testRunner = testRunner;
        }

        static int _building = -1;

        public void Consume(FileChangeMessage message)
        {
            if(!message.FullName.Contains("bin\\"))
            {
                _logger.DebugFormat(
                    "AutoTest noticed a change in folder \"{0}\". Not running tests because this is not the build folder.",
                    message.FullName);
                return;
            }

            if(!message.FullName.Contains("test"))
            {
                return;
            }
            var x = Interlocked.CompareExchange(ref _building, 1, -1);
            if(x == 1)
            {
                return;
            }
            new Thread(() =>
                {
                    var info = new FileInfo(message.FullName);
                    _logger.DebugFormat(
                        "AutoTest detected change in directory \"{0}\".",
                        info.Directory.FullName);

                    var files = info.Directory.GetFiles("*.test*.dll");
                    if(files.Length > 0)
                    {
                        var result = _testRunner.RunTests(files.First().FullName);
                        var failureCount = result.All.Where(r => r.Status == TestStatus.Failed).Count();
                        _logger.InfoFormat("AutoTest ran {0} tests with {1} failures in directory \"{2}\".",
                                           result.All.Count(), failureCount, info.Directory.FullName);

                        if(failureCount > 0)
                        {
                            StringBuilder sb = new StringBuilder();

                            foreach(var runResult in result.All.Where(r => r.Status == TestStatus.Failed))
                            {
                                sb.AppendFormat("{0}  {1}", Environment.NewLine, runResult.Message);
                            }
                            _logger.ErrorFormat("AutoTest detects failing tests - {0}", sb.ToString());
                            Console.Beep();
                        }
                    }
                    Interlocked.Exchange(ref _building, -1);
                }).Start();
        }
    }
}